<template>
  <div class="upload-box-s" :class="{ 'upload-box-s-none': listType !== 'picture-card' }">
    <el-upload
      :file-list="fileList"
      ref="uploadRef"
      :id="uuid"
      action="#"
      :name="uuid"
      :class="['upload', self_disabled ? 'disabled' : '', drag ? 'no-border' : '']"
      :multiple="props.multiple ?? true"
      :disabled="self_disabled"
      :show-file-list="showFileList ?? false"
      :http-request="handleHttpUpload"
      :before-upload="beforeUpload"
      :on-success="uploadSuccess"
      :on-error="uploadError"
      :on-change="uploadChange"
      :drag="drag"
      :accept="fileType.join(',')"
      :auto-upload="false"
      :list-type="listType ?? 'text'"
      :limit="limit ?? 100000"
      :on-remove="handleRemoveFn"
      :on-preview="handlePictureCardPreview"
    >
      <div class="upload-empty" v-show="type === 'image'">
        <slot name="empty">
          <el-icon><Plus /></el-icon>
          <!-- <span>请上传图片</span> -->
        </slot>
      </div>
      <slot v-if="slots.default"></slot>
      <el-button v-else v-show="!type" type="primary" :icon="Plus">上传文件</el-button>
    </el-upload>
    <div class="el-upload__tip">
      <slot name="tip"></slot>
    </div>
    <el-image-viewer v-if="imgViewVisible" :url-list="[`${viewImageUrl}`]" @close="imgViewVisible = false" />
  </div>
</template>

<script setup lang="ts" name="UploadImg">
import { ref, computed, inject, watch, useSlots } from "vue";
import { generateUUID } from "@/utils";
import { uploadImgs, deleteFileApi } from "@/api/modules/upload";
import { ElNotification, formContextKey, formItemContextKey, ElUpload, ElImageViewer, ElIcon, ElButton } from "element-plus";
import type { UploadProps, UploadRequestOptions, UploadFile } from "element-plus";
import { Plus } from "@element-plus/icons-vue";
const urlResource = window?.staticConfig.urlResource;

interface UploadFileProps {
  fileList: UploadFile[]; // 文件地址 ==> 必传
  api?: (params: any) => Promise<any>; // 上传文件的 api 方法，一般项目上传都是同一个 api 方法，在组件里直接引入即可 ==> 非必传
  drag?: boolean; // 是否支持拖拽上传 ==> 非必传（默认为 true）
  disabled?: boolean; // 是否禁用上传组件 ==> 非必传（默认为 false）
  fileSize?: number; // 文件大小限制 ==> 非必传（默认为 5M）
  fileType?: File.ImageMimeType[]; // 文件类型限制 ==> 非必传（默认为 ["image/jpeg", "image/png", "image/gif"]）
  height?: string; // 组件高度 ==> 非必传（默认为 150px）
  width?: string; // 组件宽度 ==> 非必传（默认为 150px）
  borderRadius?: string; // 组件边框圆角 ==> 非必传（默认为 8px）
  prefixData?: string;
  multiple: boolean;
  showFileList: boolean;
  limit: number;
  type: string;
  listType: string;
  clipboardData: Array<any>; // 剪切板数据
  params?: any; // 其余的参数传递
}
const slots = useSlots();
console.log(slots);
// 接受父组件参数
const props = withDefaults(defineProps<UploadFileProps>(), {
  fileList: () => [],
  drag: false,
  disabled: false,
  fileSize: 1024 * 10, // 10GB
  fileType: () => [], // "image/jpeg", "image/png", "image/gif"
  height: "25px",
  width: "150px",
  borderRadius: "8px",
  listType: "",
  clipboardData: () => []
});
// 生成组件唯一id
const uuid = ref("id-" + generateUUID());
const uploadRef = ref();
watch(
  () => props.fileList,
  val => {
    console.log(val);
  },
  {
    immediate: true,
    deep: true
  }
);
// 查看文件
const imgViewVisible = ref(false);
// 获取 el-form 组件上下文
const formContext = inject(formContextKey, void 0);
// 获取 el-form-item 组件上下文
const formItemContext = inject(formItemContextKey, void 0);
// 判断是否禁用上传和删除
const self_disabled = computed(() => {
  return props.disabled || formContext?.disabled;
});
let fileOrigan = [];
let formData = new FormData();
let viewImageUrl = ref("");

/**
 * @description 文件上传
 * @param options upload 所有配置项
 * */
interface UploadEmits {
  (e: "update:file-list", value: any): void;
  (e: "change", value: any): void;
}
const emit = defineEmits<UploadEmits>();

const handlePictureCardPreview: UploadProps["onPreview"] = file => {
  if (props.type === "image") {
    viewImageUrl.value = file.url;
    imgViewVisible.value = true;
  }
};
// 复制数据上传监听
watch(
  () => props.clipboardData,
  val => {
    formData = new FormData();
    fileOrigan = [];
    console.log(val);
    // 校验格式
    if (props.fileType.length) {
      [...val].forEach(item => {
        if (props.fileType.includes(item.type)) {
          fileOrigan.push(item);
          formData.append("file", item);
        }
      });
    } else {
      [...val].forEach(item => {
        fileOrigan.push(item);
        formData.append("file", item);
      });
    }

    handleHttpUpload();
  }
);

const handleHttpUpload = async (options?: UploadRequestOptions) => {
  options && formData.append("file", options.file);
  console.log(formData.getAll("file").length, fileOrigan.length, formData.getAll("file"));
  if (formData.getAll("file").length === fileOrigan.length) {
    if (props.prefixData) formData.append("prefix", props.prefixData);
    if (props.params) {
      Object.keys(props.params).forEach(key => {
        formData.append(key, props.params[key]);
      });
    }
    try {
      const api = props.api ?? uploadImgs;
      let { data } = await api(formData);
      // const path = data.map(item => item.path);
      if (props.type === "image") {
        data = data.map(item => {
          item.url = urlResource + item.path;
          return item;
        });
        data = props.fileList.concat(data);
      }
      console.log(data);
      emit("update:file-list", data);
      emit("change", data);
      formData = new FormData();
      fileOrigan = [];
      // 调用 el-form 内部的校验方法（可自动校验）
      formItemContext?.prop && formContext?.validateField([formItemContext.prop as string]);
    } catch (error) {
      formData = new FormData();
      fileOrigan = [];
      options.onError(error as any);
    }
  }
};

const uploadChange = (file: UploadFile) => {
  console.log(file);
  file.status === "ready" && fileOrigan.push(file);
  console.log(fileOrigan.length, document.getElementsByName(uuid.value)[0].files.length);
  if (
    fileOrigan.length === document.getElementsByName(uuid.value)[0].files.length &&
    fileOrigan.length !== 0 &&
    document.getElementsByName(uuid.value)[0].files.length !== 0
  ) {
    uploadRef.value.submit();
  }
};

/**
 * @description 删除文件
 * */
const handleRemoveFn = async (file: UploadFile) => {
  const data: any = props.fileList.find(item => item.name !== file.name);
  if (data.path) {
    await deleteFileApi({ path: data.path });
  }
  const path = props.fileList.filter(item => item.name !== file.name);
  // fileOrigan = fileOrigan.filter(item => item.name !== file.originalFileName);
  // formData = formData.filter(item => item.name !== file.name);
  emit("update:file-list", path);
  // delete file;
};

/**
 * @description 编辑文件
 * */
// const editImg = () => {
//   const dom = document.querySelector(`#${uuid.value} .el-upload__input`);
//   dom && dom.dispatchEvent(new MouseEvent("click"));
// };

/**
 * @description 文件上传之前判断
 * @param rawFile 选择的文件
 * */
const beforeUpload: UploadProps["beforeUpload"] = rawFile => {
  const imgSize = rawFile.size / 1024 / 1024 < props.fileSize;
  const imgType = !props.fileType.length || props.fileType.includes(rawFile.type as File.ImageMimeType);
  if (!imgType)
    ElNotification({
      title: "温馨提示",
      message: "上传文件不符合所需的格式！",
      type: "warning"
    });
  if (!imgSize)
    setTimeout(() => {
      ElNotification({
        title: "温馨提示",
        message: `上传文件大小不能超过 ${props.fileSize}M！`,
        type: "warning"
      });
    }, 0);
  return imgType && imgSize;
};

/**
 * @description 文件上传成功
 * */
const uploadSuccess = () => {
  if (formData.getAll("file").length === fileOrigan.length && formData.getAll("file").length !== 0 && fileOrigan.length !== 0) {
    formData = new FormData();
    fileOrigan = [];
    ElNotification({
      title: "温馨提示",
      message: "文件上传成功！",
      type: "success"
    });
  }
};

/**
 * @description 文件上传错误
 * */
const uploadError = () => {
  if (formData.getAll("file").length === fileOrigan.length && formData.getAll("file").length !== 0 && fileOrigan.length !== 0) {
    formData = new FormData();
    fileOrigan = [];
    ElNotification({
      title: "温馨提示",
      message: "文件上传失败，请您重新上传！",
      type: "error"
    });
  }
};
</script>

<style scoped lang="scss">
.is-error {
  .upload {
    :deep(.el-upload),
    :deep(.el-upload-dragger) {
      border: 1px dashed var(--el-color-danger) !important;
      &:hover {
        border-color: var(--el-color-primary) !important;
      }
    }
  }
}
:deep(.disabled) {
  .el-upload,
  .el-upload-dragger {
    cursor: not-allowed !important;
    background: var(--el-disabled-bg-color);
    border: 1px dashed var(--el-border-color-darker) !important;
    &:hover {
      border: 1px dashed var(--el-border-color-darker) !important;
    }
  }
}
.upload-box-s {
  .no-border {
    :deep(.el-upload) {
      border: none !important;
    }
  }
  :deep(.upload) {
    .el-upload {
      position: relative;
      display: flex;
      align-items: center;
      justify-content: center;
      width: v-bind(width);
      height: v-bind(height);
      overflow: hidden;
      border: 1px dashed var(--el-border-color-darker);
      border-radius: v-bind(borderRadius);
      transition: var(--el-transition-duration-fast);
      &:hover {
        border-color: var(--el-color-primary);
        .upload-handle {
          opacity: 1;
        }
      }
      .el-upload-dragger {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 100%;
        height: 100%;
        padding: 0;
        overflow: hidden;
        background-color: transparent;
        border: 1px dashed var(--el-border-color-darker);
        border-radius: v-bind(borderRadius);
        &:hover {
          border: 1px dashed var(--el-color-primary);
        }
      }
      .el-upload-dragger.is-dragover {
        background-color: var(--el-color-primary-light-9);
        border: 2px dashed var(--el-color-primary) !important;
      }
      .upload-image {
        width: 100%;
        height: 100%;
        object-fit: contain;
      }
      .upload-empty {
        position: relative;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        width: 80px;
        height: 80px;
        font-size: 12px;
        line-height: 30px;
        color: var(--el-color-info);
        .el-icon {
          font-size: 28px;
          color: var(--el-text-color-secondary);
        }
      }
    }
    .el-upload-list__item,
    .el-upload--picture-card {
      width: v-bind(width);
      height: v-bind(height);
      background-color: transparent;
      border-radius: v-bind(borderRadius);
    }
    .el-upload-list__item-s {
      width: v-bind(width);
      height: v-bind(height);
      background-color: transparent;
      border-radius: v-bind(borderRadius);
    }
    .upload-image {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
    .upload-handle {
      position: absolute;
      top: 0;
      right: 0;
      box-sizing: border-box;
      display: flex;
      align-items: center;
      justify-content: center;
      width: v-bind(width);
      height: v-bind(height);
      padding: 0;
      margin: 0;
      cursor: pointer;
      background: rgb(0 0 0 / 60%);
      opacity: 0;
      transition: var(--el-transition-duration-fast);
      .handle-icon {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 0 6%;
        color: aliceblue;
        .el-icon {
          margin-bottom: 15%;
          font-size: 140%;
        }
        span {
          font-size: 100%;
        }
      }
    }
    .el-upload-list__item {
      &:hover {
        .upload-handle {
          opacity: 1;
        }
      }
    }
  }
  .el-upload__tip {
    line-height: 18px;
    text-align: center;
  }
  .el-upload__cp {
    width: 80px;
    height: 80px;
    line-height: 50px;
    text-align: center;
    border: 1px dashed var(--el-border-color-darker);
  }
}
.upload-box-s-none {
  :deep(.upload) {
    .el-upload {
      width: auto;
      border: none;
    }
  }
}
</style>
